//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <bulverde.h>
#include "keypad.h"
#include "pen.h"
#include <intcbits.h>
#include <drvpub.h>
#include "calibrate.h"
#include "wm9713.h"

//#define DIRECT_HANDINPUT

//#define _DBGPEN
//#define NEEDCALIBRATE

#define TIMER_M1_INT_CLR(pOSSR) (pOSSR = OSSR_M1)
#define TIMER_M1_INT_EN(pOIER)  (pOIER |= OIER_E1)
#define TIMER_M1_INT_DIS(pOIER) (pOIER &= ~OIER_E1)

#ifdef DIRECT_HANDINPUT
#include <elapi.h>
#include "handinput.h"
static Boolean s_bHandState = FALSE;
static UInt32 s_uDirectHand = 0;
#endif

#if (_TEST_TYPE == 41)      /* Test for Runtime of ISR */
    #define SAMPLETIMES 50
    static UInt32 ulPenIsrTime[SAMPLETIMES];
    static UInt32 ulPenTimerIsrTime[SAMPLETIMES];
    static Int32 nPenIsrSampleCounter = 0;
    static Int32 nPenTimerIsrSampleCounter = 0;
#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 42)      /* Test for times of interrupt */
    static UInt32 ulCounterOfPenIsr = 0;
    static UInt32 ulCounterOfPenTimerIsr = 0;
#endif //_TEST_TYPE == 42

#if (_TEST_TYPE == 43)      /* Test for Runtime of IST */
    #define SAMPLETIMES 50
    static UInt32 ulPenISTRunTime[SAMPLETIMES];
    static Int32 nPenISTSampleCounter = 0;
#endif //_TEST_TYPE == 43


CPen tpen;
PVoid timerChannel;

UInt32 dir = TP_PEN_UP;
UInt32 xCoordinat = 0;
UInt32 yCoordinat = 0;
static Boolean bPenPush = FALSE;

static unsigned long g_PenDavCounter;
static int g_SampleStart;

static IThread * s_penThd;
DzEvent s_penEvt;
void PenTimerIsr();

ECode _InitWM9713();
void _OpenACLink();
void _CloseACLink();

void PEN_Init(void)
{
    //LNOTENOTE: must init after audio codec
    wm9712_configure();
    wm9712_configure_GPIO();
}

void PEN_EnterSelfControlMode(void)
{
    g_PenDavCounter = 0;
    g_SampleStart = 0;

    cprintf("The touch panel can work correctly now!\r\n");
}

#if defined(NEEDCALIBRATE)
#include <display_def.h>
EXTERN_C void LCD_Resume(int VGAOn);
extern DisplayContext *g_pdisCxt;

//Frame buffer address
#define HwLcdBaseAddress    (g_pdisCxt->vaBasePlane)
// Pixels per row
#define HwLCDRowPixels      240
// Pixels per column
#define HwLCDColPixels      320
// lcd dispay mode, maybe 1/2/4/8 bits-per-pixel
#define HwLCDMode           16/*bits*/
#define HwLCDPixels                 (UInt32)(HwLCDRowPixels*HwLCDColPixels)
#define LcdBufferSize               (UInt32)HwLCDPixels * HwLCDMode / 8

void DrawCrossXOR(int x, int y)
{
    void *lcdPtr = (void*)HwLcdBaseAddress;
    int i;
    int dx, dy;

    if (x < 0 || x >= HwLCDRowPixels || y < 0 || y >= HwLCDColPixels) {
        return;
    }

    //clean screen
    memset(lcdPtr, 0, LcdBufferSize);

    dx = x-9;
    dy = y-9;
    for(i=0; i<19; i++)
    {
        *((unsigned short*)lcdPtr + (dy + i)*HwLCDRowPixels + x) = 0xffff;
        *((unsigned short*)lcdPtr + y*HwLCDRowPixels + (dx + i)) = 0xffff;
    }
}

static int rand()
{
    static int state = 100;
    return state = (state * 1103515245 + 12345) & 0x7fff;
}

int ts_read(TOUCH_DATA *pInfo)
{
    DzSleep(100, NULL);//Wait for pen up

    GPCR3 |= (1<<20); // clear GPIO status
    GEDR3 |= (1<<20); // clear irq status register
    WM9712_clear_sticky();
    while((GPLR3 & (1<<20)) == 0) ;

#if 0
    pInfo->x = WM9712_ts_read_xpos();
    pInfo->y = WM9712_ts_read_ypos();
    pInfo->dir = WM9712_ts_read_pressure();
    pInfo->dir = WM9712_ts_read_pressure();
#else
    sampleADC((UInt32 *)&pInfo->x, WM9712_ADC_X);
    pInfo->dir = sampleADC((UInt32 *)&pInfo->y, WM9712_ADC_Y);
#endif

    if (pInfo->dir == 0) return FALSE;

    return TRUE;
}
#endif

Boolean PenTest(void)
{
    _OpenACLink(); // See audio driver

    PEN_Init();

    PEN_EnterSelfControlMode();

#ifdef NEEDCALIBRATE

    DzDisableIrq(10);

    Display_Init(g_pdisCxt);
    cprintf("KernLcdBaseAddr 0x%08x\n", g_pdisCxt->vaBasePlane);
    assert(0 != g_pdisCxt->vaBasePlane);

    int ret;
    int i;
    TOUCH_DATA info;

    cprintf("touch need revise, please click the touch red point\n");
    DrawCrossXOR(X1, Y1);
    ret = ts_read(&info);
    cprintf("return %d, (%d, %d)\n", info.dir, info.x, info.y);

    x1 = info.x;
    y1 = info.y;

    cprintf("please click the touch red point again\n");
    DrawCrossXOR(X2, Y2);
    ret = ts_read(&info);
    cprintf("return %d, (%d, %d)\n", info.dir, info.x, info.y);

    x2 = info.x;
    y2 = info.y;

    int X, Y;
    cprintf("(%d, %d)\t-> (%d, %d)\t", x1, y1, X1, Y1);
    GetDisplayPoint(x1, y1, &X, &Y);
    cprintf("--(%d, %d)\n", X, Y);

    cprintf("(%d, %d)\t-> (%d, %d)\t", x2, y2, X2, Y2);
    GetDisplayPoint(x2, y2, &X, &Y);
    cprintf("--(%d, %d)\n", X, Y);

#if 1
    cprintf("Verify:\n");
    for(i = 0; i < 100 ; i++) {
        int X = rand() % 230;
        int Y = rand() % 310;
        DrawCrossXOR(X, Y);
        ret = ts_read(&info);
        cprintf("return %d, (%d, %d)\n", info.dir, info.x, info.y);
        if (0 == info.dir) continue;

        cprintf("return %d, (%d, %d)\t->(%d, %d)\t",
            ret, X, Y, info.x, info.y);
        GetDisplayPoint(info.x, info.y, &X, &Y);
        cprintf("--(%d, %d)\n", X, Y);
    }
#endif
    return FALSE;
#endif

    // Close ACLINK to save power.
    // And touch driver must be initilized after audio driver.
    _CloseACLink();

    return TRUE;
}

Boolean PenWake()
{
    _InitWM9713(); // see audio driver
    return PenTest();
}

int g_bInCalibrate = 0;
DzEvent   g_CaliEvent;
int GetCalibratedPos(/*InOut*/int *x, /*InOut*/int *y)
{
    if (g_bInCalibrate) {//pen calibrate op
        cprintf("Raw (%d, %d)\n", *x, *y);
        return 0;//In calibrate
    }

    int X, Y;
    GetDisplayPoint((int)*x, (int)*y, &X, &Y);

    //cprintf("(%d, %d)\t-> (%d, %d)\n", (int)*x, (int)*y, X, Y);

#if 0
    if(X<0)     X = 0;
    if(X>239)   X = 239;
    if(Y<0)     Y = 0;
    if(Y>319)   Y = 319;
#else
    if (X < 0 || X > 239 || Y < 0 || Y > 319) return 1; // Maybe flying point
#endif
    *x = X;
    *y = Y;

    return 0;//pen normal
}

void PenEnable(Boolean bIsEnable)
{
    tpen.m_bEnable = bIsEnable;
}

void PenNotify(int eType, int nCode, void *pParam)
{
    if (tpen.m_bEnable) {
        InputNotifyByIsr(eType, nCode, pParam);
    }
}

//Same as gdi event
typedef struct DECL_PACKED __touch_pad {
    short dir;
    short x;
    short y;
}G_TOUCH_PAD, *PG_TOUCH_PAD;

ECode CPen::Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    if (pBuffer == NULL ||
        pBuffer->GetCapacity() < (int)sizeof(G_TOUCH_PAD)) {
        return E_INVALID_ARGUMENT;
    }

    MemoryBuf_<16> ebbPenData;
    ebbPenData.SetUsed(16);
    MOUSE_ST *pInfo = (MOUSE_ST *)ebbPenData.GetPayload();//source
    PG_TOUCH_PAD r = (PG_TOUCH_PAD)pBuffer->GetPayload();  //dest

    WaitResult wr;
    m_Lock.Lock(&wr);

    ECode ec = g_pEventQueues->Read(EVENT_TOUCH, 16, &ebbPenData, ppCompletionEvent);
    if (FAILED(ec)) goto EXIT;

    //Convert
    r->dir = (short)(pInfo->dir&0xff);
    r->x = (short)pInfo->x;
    r->y = (short)pInfo->y;
    pBuffer->SetUsed(sizeof(PG_TOUCH_PAD));

EXIT:
    m_Lock.Unlock();

    return ec;
}

ECode  CPen::Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf &buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

void EnQueueProc(int eType, int nCode, void *pParam);
void OnMouseDownProc(int eType, int nCode, void *pParam)
{
    if (tpen.pt.dir != TP_PEN_DOWN) return;

    g_bInCalibrate++;
    g_CaliEvent.NotifyByIsr();

    return ;
}

void OnKeyCancelProc(int eType, int nCode, void *pParam)
{
    KPD_DATA *pKey = (KPD_DATA *)pParam;
    if (pKey->keycode == 0x89/*VK_PHONE_HANG_UP*/)
    {
        g_CaliEvent.NotifyByIsr();
    }
    return ;
}

ECode PenThread(void *arg);
ECode CPen::Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf &inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec = E_ACCESS_DENIED;

    switch(nControlCode) {
        case 0:
            break;
        case 1: {//Set/Reset SampleRate
            m_Interval = *(unsigned long *)inBuffer.GetPayload();
            if (m_Interval == 0 || m_Interval >= 10) {//Reset or Invalid
                m_Interval = PEN_INTERVAL;
            }
            //cprintf("Current Touch Interval %d\n", tpen.m_Interval);
            ec = NOERROR;
            break;
        }
        case 2: {
            int ret = SetCalibrationMatrix(5, (RefPoint *)inBuffer.GetPayload());
            if (0 == ret) ec = NOERROR;
            else ec = E_FAIL;
            break;
        }
        case 3: {
            //Hook Touch & Keypad Event
            AddNotify(EVENT_TOUCH, (void*)OnMouseDownProc);
            AddNotify(EVENT_KEYPAD, (void*)OnKeyCancelProc);

            cprintf("<<<<<<<<<%d\n", g_bInCalibrate);
            g_bInCalibrate = 1;

            g_CaliEvent.Clear();
            WaitResult wr;
            g_CaliEvent.Wait(&wr, NULL);//wait for MouseDown or KeyCancel

            RefPoint P;
            P.x = P.y = P.X = P.Y = 0;
            if (g_bInCalibrate > 1/*CaliOK*/) {
                P.x = (int)tpen.pt.x;
                P.y = (int)tpen.pt.y;
                assert(pOutBuffer && pOutBuffer->GetCapacity() >= (int)sizeof(RefPoint));
                pOutBuffer->Copy((Byte *)&P, sizeof(RefPoint));
                ec = NOERROR;
            }

            cprintf(">>>>>>>>return %x, Got Raw Coordinate (%d, %d)\n", ec, P.x, P.y);
            g_bInCalibrate = 0;

            //Restore Touch & Keypad Event Hook
            AddNotify(EVENT_TOUCH, (void*)EnQueueProc);
            AddNotify(EVENT_KEYPAD, (void*)EnQueueProc);
            break;
        }

#ifdef DIRECT_HANDINPUT
        case 4: {
            // Direct hand input support
            assert(inBuffer.GetCapacity() >= (int)sizeof(int));
            ec = HandInputOpen(*(int *)inBuffer.GetPayload());
            if (SUCCEEDED(ec)) s_bHandState = TRUE;
            break;
        }

        case 5:
            HandInputClose();
            s_bHandState = FALSE;
            break;

#endif
        case 6:
            PenTest();
            break;

        case 7: {
            //Enable/Disable pen input
            assert(NULL != inBuffer.GetPayload());
            Boolean bEnable = (*(Boolean *)inBuffer.GetPayload())? true: false;
            PenEnable(bEnable);
            ec = NOERROR;
            break;
        }

#if (_TEST_TYPE == 41)
        case 4100:
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            memcpy(pOutBuffer->GetPayload(),
                    ulPenIsrTime,
                    SAMPLETIMES * sizeof(UInt32));
            pOutBuffer->SetUsed(SAMPLETIMES * sizeof(UInt32));
            ec = NOERROR;
            break;
        case 4101:
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            memcpy(pOutBuffer->GetPayload(),
                    ulPenTimerIsrTime,
                    SAMPLETIMES * sizeof(UInt32));
            pOutBuffer->SetUsed(SAMPLETIMES * sizeof(UInt32));
            ec = NOERROR;
            break;
#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 42)
        case 4200:
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            *(UInt32 *)pOutBuffer->GetPayload() = ulCounterOfPenIsr;
            pOutBuffer->SetUsed(sizeof(UInt32));
            ec = NOERROR;
            break;
        case 4201:
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            *(UInt32 *)pOutBuffer->GetPayload() = ulCounterOfPenTimerIsr;
            pOutBuffer->SetUsed(sizeof(UInt32));
            ec = NOERROR;
            break;
#endif //_TEST_TYPE == 42

#if (_TEST_TYPE == 43)
        case 4300:
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            memcpy(pOutBuffer->GetPayload(),
                    ulPenISTRunTime,
                    SAMPLETIMES * sizeof(UInt32));
            pOutBuffer->SetUsed(SAMPLETIMES * sizeof(UInt32));
            ec = NOERROR;
            break;
#endif //_TEST_TYPE == 43

        default:
            break;
    };

    return ec;
}



__inline void cwrite(unsigned char c)
{
    //STTHR = c;
}

__inline void cwrite1(unsigned char c)
{
#if !defined(_RELEASE) || defined(_PRERELEASE)
    STTHR = c;
#endif
}

static UInt32 PreX = 0;
static UInt32 PreY = 0;
static UInt32 PushX = 0;
static UInt32 PushY = 0;
static UInt32 penstamp = 0;

int CheckDistance(UInt32 x, UInt32 y)
{
    UInt32 dx = (x > PreX)?(x-PreX):(PreX-x);
    UInt32 dy = (y > PreY)?(y-PreY):(PreY-y);

    //cprintf("x %d, y %d, PreX %d, PreY %d\n", dx, dy, PreX, PreY);

    if ((dx < 10) && (dy < 10)) {
        return 1;
    }
    if ((dx > 200) || (dy > 200)) {
        return 2;
    }
//    if ((dx < 3) && (dy < 3)) {
//        return 3;
//    }

    return 0;
}

int CheckPoint(UInt32 x, UInt32 y)
{
    UInt32 dx = (x > PushX)?(x-PushX):(PushX-x);
    UInt32 dy = (y > PushY)?(y-PushY):(PushY-y);

    //cprintf("x %d, y %d, PushX %d, PushY %d\n", dx, dy, PushX, PushY);

    if ((dx < 10) && (dy < 10)) {
        return 1;
    }
    return 0;
}

//returns the number of milliseconds since boot time.
static int GetTickCount()
{
    return OSCR0 * 3;//100ns
}

void CDECL PenIsr(void *pvDevice, Boolean *bArg)
{
#if (_TEST_TYPE == 41)
    UInt32 uTimerStart = OSCR0;
#endif //_TEST_TYPE == 41

    cwrite('~');

    GPCR3 |= (1<<20); // clear GPIO status
    GEDR3 |= (1<<20); // clear irq status register
    s_penEvt.NotifyByIsr();


#if (_TEST_TYPE == 41)
    UInt32 uTimerEnd = OSCR0;
    if (nPenIsrSampleCounter >= SAMPLETIMES) nPenIsrSampleCounter = 0;
    ulPenIsrTime[nPenIsrSampleCounter++] = \
                            (uTimerEnd >= uTimerStart) ? \
                            (uTimerEnd - uTimerStart) : \
                            ((UInt32)0xFFFFFFFF - uTimerStart + uTimerEnd);
#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 42)
    ulCounterOfPenIsr++;
#endif //_TEST_TYPE == 42
}

void PenReadData()
{
#if (_TEST_TYPE == 43)
    UInt32 uTimerStart = OSCR0;
#endif //_TEST_TYPE == 43

    _OpenACLink(); // See audio driver

    cwrite('@');

    CPen *pTP = &tpen;

    // pen down or move status
    int ret = 1;
    TOUCH_DATA t;

#if 0
    t.x = WM9712_ts_read_xpos();
    t.y = WM9712_ts_read_ypos();
#endif
    sampleADC((UInt32 *)&t.x, WM9712_ADC_X);
    t.dir = sampleADC((UInt32 *)&t.y, WM9712_ADC_Y);

    WM9712_clear_sticky();

    //cprintf("return %d, (%d, %d)\n", t.dir, t.x, t.y);

    if (t.dir == 0) {//PEN_UP
        if (dir != TP_PEN_UP) PenTimerIsr();
        _CloseACLink(); // See audio driver
        return ;
    }

   //LNOTENOTE:
    if (GetCalibratedPos(&t.x, &t.y)) {
        cprintf("Maybe flying point.\n");
        return;
    }


    pTP->pt.x = xCoordinat = (UInt32)t.x;
    pTP->pt.y = yCoordinat = (UInt32)t.y;

    if(dir == TP_PEN_UP)
        pTP->pt.dir = dir =  TP_PEN_DOWN;
    else
        pTP->pt.dir = dir = TP_PEN_MOVE;

   if (dir == TP_PEN_MOVE && 0 != (ret=CheckDistance(pTP->pt.x, pTP->pt.y))) {
       if (ret == 1) {//maybe push
           if (penstamp == (UInt32)-1) {
               ;
           }
           else if (penstamp == 0) {
                penstamp = GetTickCount();
                PushX = pTP->pt.x;
                PushY = pTP->pt.y;
           }
           else if (0 == CheckPoint(pTP->pt.x, pTP->pt.y)) {
                penstamp = 0;//Reset
           }
           else {
               if (GetTickCount() - penstamp >= 1000 * 10000/*1s*/) {
                    pTP->pt.dir = dir = TP_PEN_PUSH;
#if defined(_DBGPEN)
                    cprintf("**************************\n");
                    cprintf("pen push\n");
                    cprintf("[%x] x = %d, y = %d\n", pTP->pt.dir, pTP->pt.x, pTP->pt.y);
                    cprintf("**************************\n");
#endif
                    cwrite1('P');
                    bPenPush = TRUE;
                    PenNotify(EVENT_TOUCH, 0x20, &(pTP->pt));
                    penstamp = (UInt32)-1;//bigbig enough

#ifdef DIRECT_HANDINPUT
        if (s_bHandState) HandInputReset(1);
#endif
                    goto Done;
                }
            }
        }
    }
    else {
        cwrite('r');
        if (penstamp != (UInt32)-1) penstamp = 0;//reset
    }

#if defined(_DBGPEN)
    cprintf("**************************\n");
    if (dir == TP_PEN_DOWN)
        cprintf("pen down\n");
    else
        cprintf("pen move\n");
    cprintf("[%x] x = %d, y = %d\n", pTP->pt.dir, pTP->pt.x, pTP->pt.y);
    cprintf("**************************\n");
#endif
    cwrite('0');
    PenNotify(EVENT_TOUCH, 0x20, &(pTP->pt));
    PreX = pTP->pt.x;
    PreY = pTP->pt.y;

#ifdef DIRECT_HANDINPUT
    if (s_bHandState) HandInputPutPoint((int)xCoordinat, (int)yCoordinat);
#endif

Done:

#if (_TEST_TYPE == 43)
    UInt32 uTimerEnd = OSCR0;
    if (nPenISTSampleCounter >= SAMPLETIMES) nPenISTSampleCounter = 0;
    ulPenISTRunTime[nPenISTSampleCounter++] = \
                                (uTimerEnd >= uTimerStart) ? \
                                (uTimerEnd - uTimerStart) : \
                                ((UInt32)0xFFFFFFFF - uTimerStart + uTimerEnd);
#endif //_TEST_TYPE == 43

    return ;

}

void PenTimerIsr()//PenUp
{
#if (_TEST_TYPE == 41)
    UInt32 uTimerStart = OSCR0;
#endif //_TEST_TYPE == 41

    tpen.pt.dir = dir = TP_PEN_UP;
    tpen.pt.x = xCoordinat;
    tpen.pt.y = yCoordinat;

    if (bPenPush == TRUE) {
        tpen.pt.dir = 8/*PUSH_UP*/;
        bPenPush = FALSE;
        cwrite1('U');
    }
    else {
        cwrite1('u');
    }

#if defined(_DBGPEN)
    cprintf("**************************\n");
    cprintf("pen up\n");
    cprintf("[%x] x = %d, y = %d\n", tpen.pt.dir, tpen.pt.x, tpen.pt.y);
    cprintf("**************************\n");
#endif
    cwrite('@');
    PenNotify(EVENT_TOUCH, 0x20, &(tpen.pt));

#ifdef DIRECT_HANDINPUT
    if (s_bHandState) HandInputReset(0);
#endif

    penstamp = 0;

#if (_TEST_TYPE == 41)
    UInt32 uTimerEnd = OSCR0;
    if (nPenTimerIsrSampleCounter >= SAMPLETIMES) nPenTimerIsrSampleCounter = 0;
    ulPenTimerIsrTime[nPenTimerIsrSampleCounter++] = \
                                    (uTimerEnd >= uTimerStart) ? \
                                    (uTimerEnd - uTimerStart) : \
                                    ((UInt32)0xFFFFFFFF - uTimerStart + uTimerEnd);

#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 42)
    ulCounterOfPenTimerIsr++;
#endif //_TEST_TYPE == 42

    return;

}
ECode DzGetCurrentThread(IThread **ppCurrentThread);
ECode PenThread(void *arg)
{
    tpen.m_Interval = PEN_INTERVAL;
    cprintf("Current Touch Interval %d\n", tpen.m_Interval);

    WaitResult wr;
    while (1) {
        s_penEvt.Wait(&wr, NULL);
        PenReadData();
        DzSleep(tpen.m_Interval, NULL); // The sleep time can be adjusted
    }
}

void CPen::Dispose()
{

}

ECode CPen::Initialize()
{
    m_bEnable = TRUE;
#if (_TEST_TYPE == 41)
    memset(ulPenIsrTime, 0, sizeof(UInt32) * SAMPLETIMES);
    memset(ulPenTimerIsrTime, 0, sizeof(UInt32) * SAMPLETIMES);
#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 43)
    memset(ulPenISTRunTime, 0, sizeof(UInt32) * SAMPLETIMES);
#endif //_TEST_TYPE == 43

    //Register Pen Isr
    Drv_GpioInstall(116/*B_AC97_INT*/, (void*)this, (void *) PenIsr);

    return NOERROR;
}

EXTERN_C CPen *PenNew()
{
    CPen * pTP = &tpen;
    tpen.Initialize();

    return pTP;

}

EXTERN IDeviceDriver * CDECL CreateTouch(uint_t uDeviceNo, void *pvParameter)
{
    CPen *pPen = PenNew();
    /*
     * Enable GPIO 116 for raising edge (Active High) to signal the GPIO interrupt.
     */

    cprintf("Touch Initiliaze & calibrate\n");
    PenTest();//Pen Initiliaze & calibrate

    ECode ec = DzCreateKernelThread(PenThread,
                (PVoid)pPen, CreateThreadFlag_System, ThreadPriorityRank_Normal, &s_penThd);

    if (FAILED(ec)) {
        cprintf("CreateKernelThread error\n");
        return NULL;
    }

    return pPen;
}

// type:
// 0      Init
// 1      Disable when set overlay2
// 2      Reenable when disable overlay2
EXTERN_C void PenHook(int type)
{
#ifdef DIRECT_HANDINPUT
    if (type == 0) {
        EzGetProfileInt(L"Driver", L"DirectHand", &s_uDirectHand);
        if (s_uDirectHand) {
            cprintf("Open overlay1 DirectHand input Support. \n");
            HandInputOpen(0);
            s_bHandState = TRUE;
        }
    }

    if (s_uDirectHand) {
        if (type == 1) {
            HandInputClose();
            s_bHandState = FALSE;
        }
        else if (type == 2) {
            HandInputOpen(0);
            s_bHandState = TRUE;
        }
    }
#endif
}
